#coding=utf-8
from ftplib import FTP

import os
import sys
import string
import time
import datetime
import json
import socket
import ConfigParser

class FTPSync():
    def __init__(self, host, usr, psw, local, remote, logs, fail, port=21):
        self.ftp = FTP()
        self.host = host
        self.port = port
        self.usr = usr
        self.psw = psw
        self.local = local
        
        self.remote_root = ''
        self.remote = remote

        self.remote_curr = ''
        self.remote_curr_list = []
        self.remote_curr_list_tem = []
        
        self.log_file = logs
        self.log_file_obj = open(os.path.join(self.local, self.log_file), 'a')

        self.fail_list = fail
        self.fail_list_obj = open(os.path.join(self.local, self.fail_list), 'a')

        self.bisdir = False
        self.mdftime = 0

        self.config = ConfigParser.ConfigParser()
        self.config.readfp(open("cig.ini", "rb"))
        
        self.bstart = False
        self.curr_point = self.config.get("global", "curr_point")
        self.point_arr = []
        self.point_n = 1

        self.bflock = False
      
    def __ConnectServer(self):
        timeout = 300
        socket.setdefaulttimeout(timeout)
        try:
            self.ftp.set_pasv(True) #被动模式
            print u'Connect %s:%s' %(self.host, self.port)
            self.ftp.connect(self.host, self.port)
            print u'Success %s' %(self.host)
            print u'Start logging %s' %(self.host)
            self.ftp.login(self.usr, self.psw)
            print u'A successful login %s' %(self.host)
            print self.ftp.getwelcome()
            # return True

        except Exception,e:
            print u'Connection or login failed'
            print e
            # return False

        try:
            #self.ftp.cwd(self.remotedir)
            self.ftp.cwd(self.remote)
            self.remote_root = self.ftp.pwd()

            # print 'Remote root :'+self.remote_root #/domains/56is.com/public_html

            # if self.curr_point!='':
            #     # print self.curr_point[0:self.curr_point.rfind('/')]
            #     self.remote = self.curr_point[0:self.curr_point.rfind('/')]
            #     self.ftp.cwd(self.remote)
            # else:
            #     self.ftp.cwd(self.remote)

            if self.curr_point!='':
                # print self.curr_point[0:self.curr_point.rfind('/')]
                start_point = self.curr_point[0:self.curr_point.rfind('/')]
                start_point = start_point.replace(self.remote_root,'')

                # print 'Start ponit :'+start_point

                self.point_arr = start_point.split('/')

            return True

        except Exception,e:
            print u'Directory switch failure'
            print e
            return False
      
    def __CloseServer(self):
        try:
            self.log_file_obj.close()
            self.fail_list_obj.close()
            self.ftp.quit()
            return True
        except Exception:
            return False
      
    def __CheckSizeEqual(self, remoteFile, localFile):
        try:
            # remoteFileSize = 0
            self.ftp.voidcmd('TYPE I') #二进制模式
            remoteFileSize = self.ftp.size(remoteFile)
            localFileSize = os.path.getsize(localFile)
            # print 'remoteFileSize :'+str(remoteFileSize)
            # print 'localFileSize :'+str(localFileSize)
            if localFileSize == remoteFileSize:
                return True
            else:
                return False
        except Exception,e:
            print 'Get FileSize Error! :'
            print e
            return False
          
    def __DownloadFile(self, remoteFile, localFile):
        
        try:
            
            if self.curr_point!='' and self.curr_point==self.ftp.pwd()+'/'+remoteFile:
                self.bstart = True
            
            if self.bstart:
                
                self.config.set("global", "curr_point", self.ftp.pwd()+'/'+remoteFile) #记录当前远程路径
                self.config.write(open("cig.ini", 'w'))

                bdownis = False
                if(not os.path.exists(localFile)):
                    bdownis = True
                    # print 'Modify Time :'
                else:
                    if os.stat(localFile).st_mtime < self.mdftime or not self.__CheckSizeEqual(remoteFile, localFile):
                        bdownis = True
                        # print '     ---'+str(os.stat(localFile).st_mtime)+'::'+str(self.mdftime)
                        # print '     ---Update this.'
                    else:
                        print '     ---Ignore this.'

                if bdownis:
                    self.ftp.cwd(os.path.dirname(remoteFile))
                    self.ftp.voidcmd('TYPE I') #二进制模式

                    f = open(localFile, 'wb')
                    remoteFileName = 'RETR ' + os.path.basename(remoteFile)
                    self.ftp.retrbinary(remoteFileName, f.write)
                    
                    # self.log_file_obj.write('Success to ' + localFile + '\n')

                    if self.__CheckSizeEqual(remoteFile, localFile):
                        self.log_file_obj.write(self.__getTime(1)+', Success to ' + localFile + '\n')
                        return True
                    else:
                        self.log_file_obj.write(self.__getTime(1)+', Failed to ' + localFile + '\n')
                        self.fail_list_obj.write(self.__getTime(1)+', ' + localFile + '\n') #下载不完整
                        return False
                else:
                    return True
            else:
                print '     ---Skip this.'
                return True

        except Exception,e:
            print 'Download File Error! :'
            print e
            return False
      
    def __DownloadFolder(self, remoteFolder, localFolder):

        '''
        try:
            fileList = []
            self.ftp.retrlines('LIST', fileList.append)
            #print fileList
            for remoteFile in fileList:
                #print remoteFile
                localFile = os.path.join(localFolder, remoteFile)
                #print localFile
                return self.__DownloadFile(remoteFile, localFile)
        except Exception:
            return False
        '''

        try:
            fileList = []
            # print localFolder
            if os.path.isdir(localFolder) == False:
                # print localFolder
                os.makedirs(localFolder)
                # print 'Create localFolder :'+localFolder
                # return

            self.ftp.cwd(remoteFolder)
            fileList = self.ftp.nlst()
            
            # self.__isDir("images")

            for remoteFile in fileList:
                if remoteFile != '.' and remoteFile != '..':

                    # if self.ftp.pwd().replace(self.remote_root,'')!='' and self.bflock==False: #只进行首次目录切换
                    #     localCurr = os.path.join(localFolder+self.ftp.pwd().replace(self.remote_root,'').replace('/','\\'), remoteFile)
                    # else:
                    #     localCurr = os.path.join(localFolder, remoteFile)
                    
                    # print 'localCurr :'+localCurr

                    print self.ftp.pwd()+'/'+remoteFile

                    if self.point_n < len(self.point_arr):
                        # print '     ---Continue Ponit i :'+self.point_arr[self.point_n]+'::'+remoteFile
                        if self.point_arr[self.point_n]!=remoteFile and self.point_arr[self.point_n]!='':
                            print '     ---Continue Ponit :'
                            continue

                        self.point_n = self.point_n+1

                    localCurr = os.path.join(localFolder, remoteFile)

                    self.bflock = True

                    if self.ftp.pwd()!=self.remote_curr:
                        self.remote_curr_list=[] #清空保存的列表
                        self.remote_curr = self.ftp.pwd() #记录当前路径
                    
                    # print '     ---Remote Curr :'+self.ftp.pwd()+'#'+self.remote_curr
                    
                    if self.__isDir(remoteFile):
                        # print '     ---Debug I :'
                        self.__DownloadFolder(remoteFile, localCurr)
                    else:
                        # print '     ---Debug II :'
                        self.__DownloadFile(remoteFile, localCurr)

            self.ftp.cwd('..')
            return True

        except Exception,e:
            print 'Download Folder Error! :'
            print e
            return False

    def __Show(self, lists):

        try:
            # print '     ---Debug IIII :'
            # print 'Lists :'
            # print lists
            result = lists.lower().replace('; ',';').split(';')
            # print json.dumps(lists)
            if self.path in result and 'type=dir' in result: #and "<dir>" in result:
                self.bisdir = True
                # print result
                # print 'IsDir!'

            if self.path in result and 'type=file' in result:
                for result_i in result:
                    if 'modify=' in result_i:
                        # print 'Modify :'+result_i
                        self.mdftime = int(result_i.replace('modify=', ''))
                        self.mdftime = int(time.mktime(time.strptime(str(self.mdftime), '%Y%m%d%H%M%S')))
                        # int(time.mktime(time.strptime("2013-10-10 23:40:00", "%Y-%m-%d %H:%M:%S")))
                        # print self.mdftime
            self.remote_curr_list_tem.append(lists)
            # print 'List_tem :'
            # print self.remote_curr_list_tem
        except Exception,e:
            print '     ---Debug IV :'
            print e

    def __isDir(self, path):
        self.bisdir = False
        self.path = path

        # print '     ---Debug III :'

        #this ues callback function ,that will change bisdir value
        # print self.ftp.pwd()+'::'+self.remote_curr

        # self.ftp.retrlines('MLSD', self.__Show)

        if self.ftp.pwd()==self.remote_curr and len(self.remote_curr_list)>0: #判断当前路径 减少重复获取文件列表
            # print self.remote_curr_list
            self.remote_curr_list_tem = []
            for curr_list in self.remote_curr_list:
                self.__Show(curr_list)
                # print 'Curr_list :'+curr_list
        else:
            self.remote_curr_list_tem = []
            self.ftp.retrlines('MLSD', self.__Show)
            self.remote_curr_list = self.remote_curr_list_tem
        
        return self.bisdir

    def __getTime(self, ntype):

        if ntype==1:
            return time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
        else:
            return time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))

    def SyncFromFTP(self, ntype):

        self.__ConnectServer()
        self.__DownloadFolder(self.remote, self.local)
        self.__CloseServer()

if __name__ == '__main__':
    timenow  = time.localtime()
    datenow  = time.strftime('%Y-%m-%d', timenow)
    # 配置如下变量
    hostaddr = 'ftp.globalscape.com' # ftp地址
    username = '' # 用户名
    password = '' # 密码
    port  =  21   # 端口号
    rootdir_local  = 'F:\Sync\GlobalSCAPE' # 本地目录
    rootdir_remote = '/pub' # 远程目录
    log_file = 'fileList.txt'
    fail_list = 'failList.txt'

    # local_file=[]
    # local_file = open(rootdir_local+'\\'+log_file,'wb')
    # while 1==1:

    fs = FTPSync(hostaddr, username, password, rootdir_local, rootdir_remote, log_file, fail_list, port)
    fs.SyncFromFTP(0)